import type { Commit, LocatedObject } from "./git/types.ts"; import { log, type PathChange, pathHistory } from "./git/walk.ts"; import { paginate } from "./pagination.tsx"; import { canonical, type Site, type View } from "./route.ts"; import { kindAtTip, topbar } from "./tree.tsx"; import { commitTime, plural } from "./util.ts"; const TREE = 0o040000; const HISTORY_PREFETCH = 25; async function* commitHistory( site: Site, start: string, scanned: (count: number) => void, ): AsyncGenerator { for await (const commit of log(site.repo, [start], HISTORY_PREFETCH)) { scanned(1); yield { commit, object: { oid: commit.tree, mode: TREE } }; } } const snapshotKind = (object: LocatedObject): "tree" | "blob" => (object.mode & 0o170000) === TREE ? "tree" : "blob"; export async function historyView(site: Site, view: View): Promise { const { oid, path } = view; const commitList = path.length === 0; const atTip = await kindAtTip(site, path); const list = (
    ) as HTMLOListElement; const status = (

    ) as HTMLElement; const control = (

    ) as HTMLElement; let scanned = 0; const scannedCommits = (count: number) => { scanned += count; status.textContent = `scanned ${plural(scanned, "commit")}`; }; paginate({ list, control, open: () => { scanned = 0; return commitList ? commitHistory(site, oid, scannedCommits) : pathHistory(site.repo, [oid], path, scannedCommits); }, key: change => change.commit.oid, render: change => { // rows of a file's history link to the file at that commit, not the commit's diff const target = !commitList && change.object ? canonical(site.page, { kind: snapshotKind(change.object), oid: change.commit.oid, path }, atTip) : `#commit/${change.commit.oid}`; const who = ( {change.commit.author.name} {commitTime(change.commit.author)} ) as HTMLElement; if (!change.object) who.append(deleted); const item = (

  1. ) as HTMLLIElement; if (change.commit.changeId) { item.append({change.commit.changeId.slice(0, 8)}, " "); } item.append( {change.commit.oid.slice(0, 7)}, who, {change.commit.message.split("\n")[0]}, ); return item; }, onShow: count => { status.replaceChildren({plural(count, commitList ? "commit" : "change")}); }, onError: err => { status.textContent = `history failed: ${String(err)}`; }, }); return [ await topbar(site, view, [commitList ? "commit history" : "change history"]), status, list, control, ]; }